package com.rpc.core;

import com.rpc.core.annotation.RpcImport;
import com.rpc.core.constant.ClientLoop;
import com.rpc.core.param.RpcParams;
import com.rpc.core.holder.ImportParamHolder;
import com.rpc.core.holder.bean.ImportBean;
import com.rpc.core.holder.rag.RegInfoHolder;
import com.rpc.core.proxy.ImportBeanProxy;
import com.rpc.core.register.RpcRegister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Proxy;
import java.util.*;


public class RpcImportPostProcessor implements InstantiationAwareBeanPostProcessor, InitializingBean,ApplicationContextAware, DisposableBean {

    private Logger logger = LoggerFactory.getLogger(RpcImportPostProcessor.class);

    private ApplicationContext context;

    private RpcParams params;
    private RpcRegister register;

    private List<RegInfoHolder> holderList = new ArrayList<RegInfoHolder>();

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {


        //对Bean查找 RpcImport  //4.收集本地感兴趣的信息
        ReflectionUtils.doWithFields(bean.getClass(), field -> {

            RpcImport annotation = field.getAnnotation(RpcImport.class);

            if (annotation != null) {

                //appName
                String appName = annotation.appName();
                String version = annotation.version();
                //interface
                String iname = field.getType().getName();
                String itag = iname + ":" + version;

                boolean lazy = annotation.lazy();
                //loadbalance
                String lb = annotation.lb();

                ImportParamHolder importParamHolder = new ImportParamHolder();
                importParamHolder.setAppName(appName);
                importParamHolder.setItag(itag);
                importParamHolder.setLb(lb);
                importParamHolder.setLazy(lazy);

                //监听指定的appName
                RegInfoHolder infoHolder = this.register.listen(appName);

                //5.创建远程调用客户端
                ImportBean importBean = buildImport(importParamHolder, infoHolder);

                //创建代理对象并且设置回bean
                Object obj = createProxy(field.getType(), importBean);

                field.setAccessible(true);
                field.set(bean, obj);
            }
        });

        return true;
    }

    private Object createProxy(Class iClass, ImportBean importBean) {

        return Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[]{iClass},
                new ImportBeanProxy(importBean));
    }

    private ImportBean buildImport(ImportParamHolder holder, RegInfoHolder infoHolder) {
        return new ImportBean(infoHolder, context,holder);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
        this.params = context.getBean(RpcParams.class);
    }

    @Override
    public void destroy() throws Exception {
        this.register.close();
        ClientLoop.close();
        holderList.forEach(RegInfoHolder::close);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Object reg = context.getBean(params.getRegisterType());

        if (!(reg instanceof RpcRegister)) {
            throw new RuntimeException("The registrar could not be found!");
        }
        this.register = (RpcRegister) reg;
    }
}
